package com.foton.logistic.daemon;

import android.app.Notification;
import android.app.Service;
import android.content.ComponentName;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.IBinder;
import android.support.annotation.Nullable;

import com.foton.logistic.base.BaseApplication;
import com.foton.logistic.util.LocationUtil;
import com.foton.logistic.util.tool.LogUtil;


public abstract class AbsWorkService extends Service {

    protected static final int HASH_CODE = 1;


    /**
     * 是否 任务完成, 不再需要服务运行?
     *
     * @return 应当停止服务, true; 应当启动服务, false; 无法判断, 什么也不做, null.
     */
    public abstract Boolean shouldStopService(Intent intent, int flags, int startId);

    /**
     * 业务处理
     * @param intent
     * @param flags
     * @param startId
     */
    public abstract void startWork(Intent intent, int flags, int startId);

    /**
     * 业务取消
     * @param intent
     * @param flags
     * @param startId
     */
    public abstract void stopWork(Intent intent, int flags, int startId);

    /**
     * 任务是否正在运行?
     *
     * @return 任务正在运行, true; 任务当前不在运行, false; 无法判断, 什么也不做, null.
     */
    public abstract Boolean isWorkRunning(Intent intent, int flags, int startId);

    @Nullable
    public abstract IBinder onBind(Intent intent, Void alwaysNull);

    /**
     * 清除服务
     * @param rootIntent
     */
    public abstract void onServiceKilled(Intent rootIntent);

    /**
     * 1.防止重复启动，可以任意调用startService(Intent i);
     * 2.利用漏洞启动前台服务而不显示通知;
     * 3.在子线程中运行定时任务，处理了运行前检查和销毁时保存的问题;
     * 4.启动守护服务;
     * 5.守护 Service 组件的启用状态, 使其不被 MAT 等工具禁用.
     */
    protected int onStart(Intent intent, int flags, int startId) {
        try {
            LogUtil.e("--------------starting WorkService--------------");
            //启动前台服务而不显示通知的漏洞已在 API Level 25 修复！
            if (Build.VERSION.SDK_INT <= DaemonEnv.SDKVERSION) {//24
                //利用漏洞在 API Level 17 及以下的 Android 系统中，启动前台服务而不显示通知
                startForeground(HASH_CODE, new Notification());
                //利用漏洞在 API Level 18 及以上的 Android 系统中，启动前台服务而不显示通知
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR2)
                    startService(new Intent(getApplication(), WorkNotificationService.class));
            }

            try {
                //启动守护服务，运行在:watch子进程中
                startService(new Intent(getApplication(), WatchDogService.class));
            } catch (Exception e) {
                e.printStackTrace();
            }

            //业务逻辑: 实际使用时，根据需求，将这里更改为自定义的条件，判定服务应当启动还是停止 (任务是否需要运行)
            Boolean shouldStopService = shouldStopService(intent, flags, startId);
            if (shouldStopService != null) {
                if (shouldStopService) {
                    stopService(intent, flags, startId);
                } else {
                    startService(intent, flags, startId);

                }
            }

            //若定位服务停止，重新唤醒
            new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (LocationUtil.getInstance() != null) {
                        LocationUtil.getInstance().keepLocation("" + BaseApplication.LOCTIME);
                    }
                }
            }, 3000);


            registerBroadcast();

            //守护 Service 组件的启用状态, 使其不被 MAT 等工具禁用
            getPackageManager().setComponentEnabledSetting(new ComponentName(getPackageName(), WatchDogService.class.getName()),
                    PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP);
            LogUtil.e("--------------start WorkService success--------------");
        } catch (Exception e) {
            e.printStackTrace();
        }

        return START_STICKY;
    }

    void startService(Intent intent, int flags, int startId) {
        try {
            //检查服务是否不需要运行
            Boolean shouldStopService = shouldStopService(intent, flags, startId);
            if (shouldStopService != null && shouldStopService) {
                return;
            }
            //若还没有取消订阅，说明任务仍在运行，为防止重复启动，直接 return
            Boolean workRunning = isWorkRunning(intent, flags, startId);
            if (workRunning != null && workRunning) {
                return;
            }
            //业务逻辑
            startWork(intent, flags, startId);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 停止服务并取消定时唤醒
     * <p>
     * 停止服务使用取消订阅的方式实现，而不是调用 Context.stopService(Intent name)。因为：
     * 1.stopService 会调用 Service.onDestroy()，而 AbsWorkService 做了保活处理，会把 Service 再拉起来；
     * 2.我们希望 AbsWorkService 起到一个类似于控制台的角色，即 AbsWorkService 始终运行 (无论任务是否需要运行)，
     * 而是通过 onStart() 里自定义的条件，来决定服务是否应当启动或停止。
     */
    void stopService(Intent intent, int flags, int startId) {
        //取消对任务的订阅
        stopWork(intent, flags, startId);
        //取消 Job / Alarm / Subscription
        KeepLiveManager.getInstance().cancelJobAlarmSub();
    }

    @Override
    public int onStartCommand(Intent intent, int flags, int startId) {
        return onStart(intent, flags, startId);
    }

    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
        onStart(intent, 0, 0);
        return onBind(intent, null);
    }

    protected void onEnd(Intent rootIntent) {
        try {
            onServiceKilled(rootIntent);
            if (!DaemonEnv.sInitialized) return;
            startService(new Intent(DaemonEnv.sApp, DaemonEnv.sServiceClass));
            startService(new Intent(DaemonEnv.sApp, WatchDogService.class));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 最近任务列表中划掉卡片时回调
     */
    @Override
    public void onTaskRemoved(Intent rootIntent) {
        onEnd(rootIntent);
    }

    /**
     * 设置-正在运行中停止服务时回调
     */
    @Override
    public void onDestroy() {
        onEnd(null);
        try {
            unregisterReceiver(wakeUpReceiver);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static class WorkNotificationService extends Service {

        /**
         * 利用漏洞在 API Level 18 及以上的 Android 系统中，启动前台服务而不显示通知
         */
        @Override
        public int onStartCommand(Intent intent, int flags, int startId) {
            try {
                startForeground(AbsWorkService.HASH_CODE, new Notification());
                stopSelf();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return START_STICKY;
        }

        @Override
        public IBinder onBind(Intent intent) {
            return null;
        }
    }

    private WakeUpReceiver wakeUpReceiver;

    private void registerBroadcast(){
        try {
            if (wakeUpReceiver == null){
                wakeUpReceiver = new WakeUpReceiver();
                IntentFilter receiverFilter=new IntentFilter();
                receiverFilter.addAction(WakeUpReceiver.ACTION_CANCEL_JOB_ALARM_SUB);
//                receiverFilter.addAction(Intent.ACTION_BOOT_COMPLETED);
                receiverFilter.addAction(Intent.ACTION_MEDIA_MOUNTED);
                receiverFilter.addAction(Intent.ACTION_POWER_CONNECTED);
                receiverFilter.addAction(Intent.ACTION_POWER_DISCONNECTED);
                receiverFilter.addAction(Intent.ACTION_USER_PRESENT);
                receiverFilter.addAction(Intent.ACTION_SCREEN_ON);
                receiverFilter.addAction(Intent.ACTION_SCREEN_OFF);
//                receiverFilter.addDataScheme("file");
                registerReceiver(wakeUpReceiver, receiverFilter);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
